package com.logistics.map.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.logistics.dictionary.entity.model.DictionaryRow;
import com.logistics.dictionary.service.DictionaryService;
import com.logistics.inventory.entity.domain.Inventory;
import com.logistics.inventory.entity.domain.InventoryDetail;
import com.logistics.inventory.service.InventoryDetailService;
import com.logistics.inventory.service.InventoryService;
import com.logistics.map.entity.domain.MapComponents;
import com.logistics.map.entity.model.*;
import com.logistics.map.mapper.MapComponentsMapper;
import com.logistics.qrcode.entity.domain.Qrcode;
import com.logistics.qrcode.service.QrcodeService;
import com.logistics.rcs.entity.model.RcsCoordinateRow;
import com.logistics.rcs.service.RcsService;
import com.logistics.utils.aspect.annotation.Insert;
import com.logistics.utils.aspect.annotation.Pager;
import com.logistics.utils.bean.ResultPager;
import com.logistics.utils.constants.Constants;
import com.logistics.utils.constants.Message;
import com.logistics.utils.exception.MessageException;
import com.logistics.utils.message.Manager;
import com.logistics.utils.tool.StringUtils;
import groovy.lang.Lazy;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class MapComponentsService extends ServiceImpl<MapComponentsMapper, MapComponents> {

    @Autowired
    private DictionaryService dictionaryService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    @Lazy
    private InventoryDetailService inventoryDetailService;

    @Autowired
    private RcsService rcsService;

    @Autowired
    private QrcodeService qrcodeService;

    @Autowired
    private MapComponentsMapper mapComponentsMapper;

    /**
     * 保存地图组件
     *
     * @param save
     */
    @Insert
    public void save(MapComponentsSave save) {
        this.save(MapComponents.build(save));
    }

    /**
     * 删除地图组件
     *
     * @param ids
     * @throws MessageException
     */
    public void removeById(String ids) throws MessageException {
        if (StringUtils.isNull(ids)) {
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        this.remove(new LambdaQueryWrapper<MapComponents>().in(MapComponents::getId,
                StringUtils.splitToList(ids, ",")));
    }

    /**
     * 根据地图ID删除
     *
     * @param ids
     * @throws MessageException
     */
    public void removeByMapId(String ids) throws MessageException {
        if (StringUtils.isNull(ids)) {
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        this.remove(new LambdaQueryWrapper<MapComponents>().in(MapComponents::getMapId,
                StringUtils.splitToList(ids, ",")));
    }

    /**
     * 更加ID查找组件信息
     *
     * @param mapId
     * @return
     */
    public List<MapComponentsRow> byMapId(String mapId) {
        return this.list(new LambdaQueryWrapper<MapComponents>().in(MapComponents::getMapId, mapId))
                .stream().map(e -> MapComponentsRow.build(e)).collect(Collectors.toList());
    }

    /**
     * 查找站点信息
     *
     * @return
     * @throws MessageException
     */
    public List<SiteRow> siteRows() throws MessageException {
        List<DictionaryRow> dictionaryRows = dictionaryService.listByTypes("workshop").get(0).getChildren();
        List<String> codes = dictionaryRows.stream().map(e -> e.getCode()).collect(Collectors.toList());
        List<MapComponents> componentsRows = this.list(new LambdaQueryWrapper<MapComponents>().
                in(MapComponents::getWorkshop, codes).eq(MapComponents::getClazz, Constants.COMPONENTS_TYPE_LOCATION));
        return dictionaryRows.stream().map(e ->
                SiteRow.build(e.getCode(), e.getName(), getChildren(e.getCode(), componentsRows))
        ).collect(Collectors.toList());
    }

    /**
     * 查找设备类型
     *
     * @param deviceId
     * @return
     */
    public MapComponents agvTypeByDeviceId(String deviceId) {
        MapComponents result = this.
                getOne(new LambdaQueryWrapper<MapComponents>()
                        .eq(MapComponents::getDeviceId, deviceId).eq(MapComponents::getClazz, Constants.COMPONENTS_TYPE_CAR));
        if (StringUtils.isNotNull(result)) {
            return result;
        }
        return null;
    }

    /**
     * 获取取货地址
     *
     * @param sizeId
     * @return
     */
    public String getLocation(String sizeId) throws MessageException {
        MapComponents result = this.getOne(new LambdaQueryWrapper<MapComponents>().eq(MapComponents::getId, sizeId));
        if (StringUtils.isNull(result)) {
            throw new MessageException(Manager.getMessage(Message.MSG1013.getCode()));
        }
        return result.getLocation();
    }

    public List<SiteRow> getChildren(String code, List<MapComponents> components) {
        return components.stream().filter(e -> StringUtils.isEquals(code, e.getWorkshop())).
                map(e -> SiteRow.build(e.getId().toString(), e.getLabel())).collect(Collectors.toList());
    }

    /**
     * 校验站点码是否为正确的站点码（防误扫描）
     * @param station
     * @return
     */
//    public MapComponents siteCodeExists(String station) throws MessageException {
//         List<MapComponents> mapComponentsList = this.list(new LambdaQueryWrapper<MapComponents>()
//                .eq(MapComponents :: getClazz, Constants.COMPONENTS_TYPE_LOCATION)
//                 .eq(MapComponents :: getLocation, station));
//        if (mapComponentsList.isEmpty()){
//            throw new MessageException("站点码不存在，请重新扫描");
//        }
//    }

    /**
     * 查找托盘的 MapComponents
     *
     * @param stationList
     * @return
     */
    public List<MapComponents> getLocationByPallet(List<String> stationList) {
        return this.list(new LambdaQueryWrapper<MapComponents>()
                .eq(MapComponents::getClazz, Constants.COMPONENTS_TYPE_LOCATION)
                .in(MapComponents::getLocation, stationList));
    }

    /**
     * 根据站点查找地图信息
     *
     * @param station
     * @return
     */
    public MapComponents getLocationByStation(String station) throws MessageException {
        MapComponents components = this.getOne(new LambdaQueryWrapper<MapComponents>()
                .eq(MapComponents::getClazz, Constants.COMPONENTS_TYPE_LOCATION)
                .eq(MapComponents::getLocation, station));

        if (components == null) {
            throw new MessageException("站点无效");
        }
        return components;
    }

    /**
     * 根据zone和wcCode 查找符合条件的空托存放区
     *
     * @param zone
     * @param trayNum
     * @return List<MapComponents>
     * @throws MessageException
     */
    public List<MapComponents> getStorageArea(String zone, int trayNum) throws MessageException {
        return this.list(new LambdaQueryWrapper<MapComponents>()
                .eq(MapComponents::getZone, zone)
                .eq(MapComponents::getLocationWcCode, "空托存放区")
                .ge(MapComponents::getCurrentStratum, trayNum));
    }

    /**
     * 获取Agv列表
     *
     * @return
     * @throws MessageException
     */
    public List<SiteRow> getAgvList() throws MessageException {
        List<MapComponents> componentsRows = this.list(new LambdaQueryWrapper<MapComponents>().
                eq(MapComponents::getClazz, Constants.COMPONENTS_TYPE_CAR).orderByAsc(MapComponents::getDeviceId));
        return componentsRows.stream().map(e ->
                        SiteRow.build(e.getDeviceId(), e.getDeviceId()))
                .collect(Collectors.toList());
    }

    /**
     * 获取地图上的站点和货物信息
     *
     * @return List<ComponentsEventRow>
     */
    public List<ComponentsEventRow> locationAndGoods() {
        //获取MapComponents所有数据
        List<MapComponents> locations = this.list(new LambdaQueryWrapper<MapComponents>().
                eq(MapComponents::getClazz, Constants.COMPONENTS_TYPE_LOCATION));
        //获取MapComponents所有点位信息
        List<String> points = locations.stream().map(MapComponents::getLocation)
                .collect(Collectors.toList());
        //根据点位查询库存信息
        List<Inventory> inventoryRows = inventoryService.getInventoryByPoint(points);
        // 所有托盘
        List<String> containerList = inventoryRows.stream()
                .map(Inventory::getContainer)
                .distinct() // 避免重复获取相同的托盘
                .collect(Collectors.toList());
        //获取托盘对应的ContainerDetail信息
        Map<String, List<InventoryDetail>> containerToDetailMap = inventoryDetailService.getByContainer(containerList).stream().
                collect(Collectors.groupingBy(InventoryDetail::getContainer));

        Map<String, String> stationToContainersMap = inventoryRows.stream()
                .collect(Collectors.groupingBy(
                        Inventory::getStation,
                        Collectors.mapping(Inventory::getContainer, Collectors.joining(","))
                ));
        // 获取点位对应的坐标
        Map<String, RcsCoordinateRow> coordinateMaps = rcsService.coordinateRows(points.stream().filter(StringUtils::isNotNull).map(item -> item.split("-")[1])
                        .collect(Collectors.toList())).stream().
                collect(Collectors.toMap(RcsCoordinateRow::getPoint, coordinateRow -> coordinateRow));
        return locations.stream().filter(e -> StringUtils.isNotNull(e.getLocation())).map(item -> {
            String container = stationToContainersMap.get(item.getLocation());
            ComponentsEventRow row = ComponentsEventRow.build(container, containerToDetailMap.get(container), item);
            String key = item.getLocation().split("-")[1];
            if (StringUtils.isNotNull(coordinateMaps.get(key))) {
                row.setX(coordinateMaps.get(key).getX());
                row.setY(coordinateMaps.get(key).getY());
                MapComponents mapComponents = new MapComponents();
                mapComponents.setX(coordinateMaps.get(key).getX());
                mapComponents.setY(coordinateMaps.get(key).getY());
                this.update(mapComponents, new LambdaQueryWrapper<MapComponents>().eq(MapComponents::getLocation, item.getLocation()));
            }else{
                row.setX(null);
                row.setY(null);
            }
            return row;
        }).collect(Collectors.toList());
    }

    /**
     * 站点主数据分页查询
     *
     * @param param
     * @return
     */
    @Pager
    public ResultPager pager(MapComponentsPager param) {
        IPage<MapComponents> page = new Page<>(param.getCurrent(), param.getPageSize());
        LambdaQueryWrapper<MapComponents> queryWrapper = Wrappers.lambdaQuery();
        if (param.getComponentClazz().equals(Constants.COMPONENTS_TYPE_LOCATION)) {
            queryWrapper.eq(MapComponents::getClazz, param.getComponentClazz())
                    .like(StringUtils.isNotNull(param.getLabel()), MapComponents::getLabel, param.getLabel())
                    .like(StringUtils.isNotNull(param.getLocation()), MapComponents::getLocation, param.getLocation())
                    .like(StringUtils.isNotNull(param.getLocationArea()), MapComponents::getLocationArea, param.getLocationArea());
        }else if (param.getComponentClazz().equals(Constants.COMPONENTS_TYPE_CAR)) {
            queryWrapper.eq(MapComponents::getClazz, param.getComponentClazz())
                    .eq(StringUtils.isNotNull(param.getAgvType()), MapComponents::getAgvType, param.getAgvType())
                    .like(StringUtils.isNotNull(param.getDeviceId()), MapComponents::getDeviceId, param.getDeviceId());
        }
        IPage<MapComponents> result = this.page(page, queryWrapper);
        return new ResultPager<>(result.getRecords().stream()
                .map(MapComponentsRow::build).collect(Collectors.toList()), (int) result.getTotal());
    }

    /**
     * 保存站点信息
     * @param save
     * @throws MessageException
     */
    @Insert
    public void saveStation(MapComponentsSave save) throws MessageException{
        if (StringUtils.isNotNull(save.getId())) {
            this.updateById(MapComponents.build(save));
            qrcodeService.update(Qrcode.build(save), new LambdaUpdateWrapper<Qrcode>().eq(Qrcode :: getCode, save.getLabel()));
        }else {
            MapComponents mapComponents = this.getOne(new LambdaQueryWrapper<MapComponents>().eq(MapComponents :: getLabel, save.getLabel()));
            Qrcode qrcode = qrcodeService.findByCode(save.getLabel());
            if (StringUtils.isNull(mapComponents) && StringUtils.isNull(qrcode)){
                MapComponentsSave.build(save,1,"location",UUID.randomUUID().toString(),"4",false,"#000");
                this.save(save);
                qrcodeService.save(save);
            }else {
                throw new MessageException("该站点已经存在");
            }
        }

    }
    @Insert
    public void saveAgv(MapComponentsSave save)throws MessageException{
        if (StringUtils.isNotNull(save.getId())) {
            this.updateById(MapComponents.build(save));
        }else {
            MapComponents mapComponents = this.getOne(new LambdaQueryWrapper<MapComponents>().eq(MapComponents :: getLabel, save.getLabel()));
            MapComponentsSave.build(save,1,"car",UUID.randomUUID().toString(),"4",false,"#000");
            if (StringUtils.isNull(mapComponents)){
                this.save(save);
            }else {
                throw new MessageException("该AGV已经存在");
            }
        }
    }

    /**
     * 删除站点信息
     * @param ids
     * @throws MessageException
     */
    public void delete(String ids) throws MessageException {
        if (StringUtils.isNull(ids)) {
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        List<String> codes =  this.list(new LambdaQueryWrapper<MapComponents>().
                in(MapComponents :: getId, StringUtils.splitToList(ids, ","))).
                stream().map(MapComponents :: getLabel).collect(Collectors.toList());
        qrcodeService.deleteByCodes(codes);
        this.remove(new LambdaQueryWrapper<MapComponents>().in(MapComponents :: getId, StringUtils.splitToList(ids, ",")));
    }

    /**
     * 查询站点详细
     * @param id
     * @return
     * @throws MessageException
     */
    public MapComponentsRow details(String id) throws MessageException{
        if (StringUtils.isNull(id)) {
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        return MapComponentsRow.build(mapComponentsMapper.siteById(Integer.parseInt(id)));
    }

    /**
     * 查询AGV详细
     * @param id
     * @return
     * @throws MessageException
     */
    public MapComponentsRow agvDetail(String id) throws MessageException{
        if (StringUtils.isNull(id)) {
            throw new MessageException(Manager.getMessage(Message.MSG1005.getCode()));
        }
        return MapComponentsRow.build(this.getOne(new LambdaQueryWrapper<MapComponents>()
                .eq(MapComponents::getId, id)
                .eq(MapComponents::getClazz, "car")));

    }

    /**
     * 解锁站点
     * @param uuid
     */
    public void unLockLocation(String uuid){
        this.update(MapComponents.build(false),
                new LambdaQueryWrapper<MapComponents>().eq(MapComponents::getUuid, uuid));
    }

}